package com.lapelife.backend.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lapelife.backend.common.ErrorCode;
import com.lapelife.backend.common.RedisContains;
import com.lapelife.backend.common.ResponseResult;
import com.lapelife.backend.model.domain.LoginUser;
import com.lapelife.backend.model.domain.Post;
import com.lapelife.backend.model.domain.PostUser;
import com.lapelife.backend.model.request.PageRequest;
import com.lapelife.backend.service.PostService;
import com.lapelife.backend.service.PostUserService;
import com.lapelife.backend.mapper.PostUserMapper;
import com.lapelife.backend.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author Mir.Lliao
 * @description 针对表【t_post_user(文章用户关联表)】的数据库操作Service实现
 * @createDate 2023-05-07 20:04:08
 */
@Service
public class PostUserServiceImpl extends ServiceImpl<PostUserMapper, PostUser>
        implements PostUserService {

    private RedisUtil redisUtil;

    private PostService postService;

    private PostUserMapper postUserMapper;

    private final long time = 60 * 60 * 24;

    @Autowired
    public void setPostService(PostService postService) {
        this.postService = postService;
    }

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    @Autowired
    public void setPostUserMapper(PostUserMapper postUserMapper) {
        this.postUserMapper = postUserMapper;
    }

    @Override
    public ResponseResult<String> thumbs(String flag, Long id) {
        if (id == null) {
            return ResponseResult.fail(ErrorCode.PARAMS_ERROR);
        }
        String s = RedisContains.POST_THUMBS + id;
        long l;
        int f = flag != null && flag.equals("0") ? 0 : 1;

        Integer result = addToRedis(RedisContains.THUMB, id, f);

        if (result == -1) {
            if (f == 0) {
                l = redisUtil.setRemove(s, getUserId());
            } else {
                l = redisUtil.sSet(s, getUserId());
            }
            return ResponseResult.suc(String.valueOf(l));
        }

        return ResponseResult.suc(String.valueOf(result));
    }

    @Override
    public boolean saveOrUpdate(PostUser entity) {
        LambdaQueryWrapper<PostUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PostUser::getPostId,entity.getPostId()).eq(PostUser::getUserId,entity.getUserId());
        int i = postUserMapper.countByPostIdAndUserId(entity.getPostId(), entity.getUserId());
        boolean b;
        if (i > 0) {
            b = update(entity, wrapper);
        }else {
            b = save(entity);
        }
        return b;
    }

    @Override
    public ResponseResult<String> collect(String flag, Long id) {
        if (id == null) {
            return ResponseResult.fail(ErrorCode.PARAMS_ERROR);
        }
        String s = RedisContains.POST_COLLECT + id;
        long l;
        int f = flag != null && flag.equals("0") ? 0 : 1;

        Integer result = addToRedis(RedisContains.COLLECT, id, f);

        if (result == -1) {
            if (f == 0) {
                l = redisUtil.setRemove(s, getUserId());
            } else {
                l = redisUtil.sSet(s, getUserId());
            }
            return ResponseResult.suc(String.valueOf(l));
        }

        return ResponseResult.suc(String.valueOf(result));
    }

    @Override
    public ResponseResult<String> look(Long id) {
        if (id == null) {
            return ResponseResult.fail(ErrorCode.PARAMS_ERROR);
        }
        String s = RedisContains.POST_LOOK + id;

        Integer result = addToRedis(RedisContains.LOOK, id, 1);
        LambdaQueryWrapper<PostUser> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(PostUser::getUserId, getUserId()).eq(PostUser::getPostId, id);
        long count = count(wrapper1);
        if (count == 0) {
            PostUser postUser = new PostUser();
            postUser.setPostId(id);
            postUser.setUserId(getUserId());
            postUser.setThumbFlag(redisUtil.sHasKey(RedisContains.POST_THUMBS+id,getUserId())?"1":"0");
            postUser.setCollectFlag(redisUtil.sHasKey(RedisContains.POST_COLLECT + id, getUserId()) ? "1" : "0");
            save(postUser);
        }
        if (result == -1) {
            long incr = redisUtil.incr(s, 1);
            return ResponseResult.suc(String.valueOf(incr));
        }
        return ResponseResult.suc(String.valueOf(result));
    }

    @Override
    public ResponseResult<Integer> getNum(String key, Long id) {
        if (id == null || key == null) {
            return ResponseResult.fail(ErrorCode.PARAMS_ERROR);
        }
        Object l = 0;
        addToRedis(key, id, -1);
        if (key.equalsIgnoreCase(RedisContains.THUMB)) {
            l = redisUtil.sGetSetSize(RedisContains.POST_THUMBS + id);
        }
        if (key.equalsIgnoreCase(RedisContains.COLLECT)) {
            l = redisUtil.sGetSetSize(RedisContains.POST_COLLECT + id);
        }
        if (key.equalsIgnoreCase(RedisContains.LOOK)) {
            l = redisUtil.get(RedisContains.POST_LOOK + id);
        }
        Integer num = Convert.convert(Integer.class, l);
        return ResponseResult.suc(num);
    }

    @Override
    public ResponseResult<Page<Long>> findPostIdListByCollect(PageRequest pageRequest) {
        Page<Long> page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize());
        LambdaQueryWrapper<PostUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(PostUser::getPostId).eq(PostUser::getUserId, getUserId()).eq(PostUser::getCollectFlag, "1").orderByDesc(PostUser::getLookTime);

        Page<PostUser> postUserPage = page(new Page<>(pageRequest.getCurrent(), pageRequest.getSize()), wrapper);
        List<Long> idList = new ArrayList<>();
        postUserPage.getRecords().forEach(v -> idList.add(v.getPostId()));
        page.setTotal(postUserPage.getTotal());
        page.setRecords(idList);

        return ResponseResult.suc(page);
    }

    @Override
    public ResponseResult<Page<Long>> findPostIdListByLook(PageRequest pageRequest) {
        Page<Long> page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize());
        LambdaQueryWrapper<PostUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(PostUser::getPostId).eq(PostUser::getUserId, getUserId()).orderByDesc(PostUser::getLookTime);

        Page<PostUser> postUserPage = page(new Page<>(pageRequest.getCurrent(), pageRequest.getSize()), wrapper);
        List<Long> idList = new ArrayList<>();
        postUserPage.getRecords().forEach(v -> idList.add(v.getPostId()));
        page.setTotal(postUserPage.getTotal());
        page.setRecords(idList);

        return ResponseResult.suc(page);
    }

    @Override
    public ResponseResult<Map<String,Integer>> getAllNum(Long id) {
        if (id == null) {
            return ResponseResult.fail(ErrorCode.PARAMS_ERROR);
        }
        Map<String, Integer> map = new HashMap<>();
        Post post = new Post();
        post.setPostId(id);
        Object l;
        // 点赞
        addToRedis(RedisContains.THUMB, id, -1);
        l = redisUtil.sGetSetSize(RedisContains.POST_THUMBS + id);
        map.put("thumbs", Convert.convert(Integer.class, l));
        // 收藏
        addToRedis(RedisContains.COLLECT, id, -1);
        l = redisUtil.sGetSetSize(RedisContains.POST_COLLECT + id);
        map.put("collects", Convert.convert(Integer.class, l));
        // 阅读
        addToRedis(RedisContains.LOOK, id, -1);
        l = redisUtil.get(RedisContains.POST_LOOK + id);
        map.put("looks", Convert.convert(Integer.class, l));
        map.put("thumbFlag", redisUtil.sHasKey(RedisContains.POST_THUMBS + id, getUserId()) ? 1 : 0);
        map.put("collectFlag", redisUtil.sHasKey(RedisContains.POST_COLLECT + id, getUserId()) ? 1 : 0);
        return ResponseResult.suc(map);
    }

    @Override
    public void addUserPostInfoToRedis(Long id) {
        LambdaQueryWrapper<PostUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PostUser::getUserId,id);
        List<PostUser> list = list(wrapper);
        List<Long> collectIds = new ArrayList<>();
        List<Long> thumbsIds = new ArrayList<>();
        for (PostUser postUser : list) {
            if (postUser.getCollectFlag().equals("1")) {
                collectIds.add(postUser.getPostId());
            }
            if (postUser.getThumbFlag().equals("1")) {
                thumbsIds.add(postUser.getPostId());
            }
        }
        collectIds.forEach(v->{
            String key = RedisContains.POST_COLLECT + v;
            if (redisUtil.sGet(key).size() == 0) {
                redisUtil.sSetAndTime(key, time, id);
            }else {
                redisUtil.sSet(key, id);
            }
        });
        thumbsIds.forEach(v->{
            String key = RedisContains.POST_THUMBS + v;
            if (redisUtil.sGet(key).size() == 0) {
                redisUtil.sSetAndTime(key, time, id);
            }else {
                redisUtil.sSet(key, id);
            }
        });
    }

    private Long getUserId() {
        // 获取用户信息
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return loginUser.getSysUser().getUserId();
    }

    private Integer addToRedis(String key, Long id, Integer flag) {
        LambdaQueryWrapper<PostUser> wrapper = null;
        String s = "";
        if (key.equalsIgnoreCase(RedisContains.THUMB)) {
            s = RedisContains.POST_THUMBS + id;
            if (redisUtil.sGet(s).size() == 0) {
                wrapper = new LambdaQueryWrapper<>();
                wrapper.select(PostUser::getUserId).eq(PostUser::getPostId, id).eq(PostUser::getThumbFlag, "1");
            }
        }

        if (key.equalsIgnoreCase(RedisContains.COLLECT)) {
            s = RedisContains.POST_COLLECT + id;
            if (redisUtil.sGet(s).size() == 0) {
                wrapper = new LambdaQueryWrapper<>();
                wrapper.select(PostUser::getUserId).eq(PostUser::getPostId, id).eq(PostUser::getCollectFlag, "1");
            }
        }
        if (wrapper != null) {
            List<PostUser> list = list(wrapper);
            List<Long> idList = new ArrayList<>();
            if (list != null) {
                list.forEach(v -> idList.add(v.getUserId()));
            }
            if(flag == 1){
                idList.add(getUserId());
            }
            if (idList.size() > 0) {
                long l = redisUtil.sSetAndTime(s, time, idList.toArray());
                long r = 0;
                if (flag == 0) {
                    r = redisUtil.setRemove(s, getUserId());
                }
                return Convert.convert(Integer.class, l - r);
            }
        }

        if (key.equalsIgnoreCase(RedisContains.LOOK)) {
            s = RedisContains.POST_LOOK + id;
            if (redisUtil.get(s) == null) {
                Post post = postService.getById(id);
                if (post == null) {
                    return -2;
                }
                Integer looks = post.getLooks();
                if (flag == 1) {
                    looks += 1;
                }
                boolean b = redisUtil.set(s, looks, time);
                return b ? 1 : 0;
            }
        }
        return -1;
    }
}




